package movieGandalf.GUI;

import java.math.BigInteger;
import java.sql.Connection;
import java.text.Collator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import movieGandalf.GUI.GUIManager.StatusEnum;
import movieGandalf.common.Log;
import movieGandalf.database.MovieTools;
import movieGandalf.logicGuiConnection.Genre;
import movieGandalf.logicGuiConnection.Movie;
import movieGandalf.logicGuiConnection.User;
import movieGandalf.search.ActorNameParam;
import movieGandalf.search.DirectorNameParam;
import movieGandalf.search.GenreIDParam;
import movieGandalf.search.LanguageIDParam;
import movieGandalf.search.MaxLengthParam;
import movieGandalf.search.MinRankParam;
import movieGandalf.search.MinYearParam;
import movieGandalf.search.SearchParam;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;



public class SearchPage extends Composite {

	private static final int X_MARGIN = 25;
	private static final int Y_MARGIN = 10;
	private static final int TEXT_FIELD_WIDTH = 260;
	private static final int LABEL_Y_SPACING = 20;
	private static final int LABEL_TEXT_DIFF = -3;
	private static final int LABEL_TEXT_SPACING = 50;
	
	
	private static final int NAME_WIDTH = 350;
	private static final int RANK_WIDTH = 60;
	private static final int YEAR_WIDTH = 60;
	private static final int WL_WIDTH = 100;
	private static final int GENRE_WIDTH = 200;
	private static final int LEN_WIDTH = 60;
	
	
	private static final int GANDALF_IMAGE_SIZE = 256;
	
	private Button btnSearch;
	private Table searchResultsTable;
	
	private User user;
	
	private List<Movie> results;
//	private Map<SearchParam, Object> searchMap;
//	private Map<SearchParamEnum, Text> textFields;
	private List<SearchParam> textFields;

	final String[] titles = { "Genre", "Actors", "Year", "Language", "Color",  
			"Length", "Rank", "Director"};


	public SearchPage(Composite parent, int style, User u) {
		super(parent, style);
		this.user=u;
		
		setLayout(new FormLayout());

		Label lblGenre = new Label(this, SWT.NONE);
		lblGenre.setText("Genre:");
		FormData fd_lblGenre = new FormData();
		fd_lblGenre.top = new FormAttachment(0, Y_MARGIN);
		fd_lblGenre.left = new FormAttachment(0, X_MARGIN);
		lblGenre.setLayoutData(fd_lblGenre);

		final Text genreSearchText = new Text(this, SWT.BORDER);
		FormData fd_genreSearchText = new FormData();
		fd_genreSearchText.top = new FormAttachment(lblGenre, LABEL_TEXT_DIFF, SWT.TOP);
		fd_genreSearchText.width = TEXT_FIELD_WIDTH;
		fd_genreSearchText.left = new FormAttachment(lblGenre, LABEL_TEXT_SPACING);
		genreSearchText.setLayoutData(fd_genreSearchText);
	

		Label lblActors = new Label(this, SWT.NONE);
		lblActors.setText("Actors:");
		FormData fd_lblActors = new FormData();
		fd_lblActors.top = new FormAttachment(lblGenre, LABEL_Y_SPACING);
		fd_lblActors.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblActors.setLayoutData(fd_lblActors);
		
		final Text actorsSearchText = new Text(this, SWT.BORDER);
		FormData fd_ActorsSearch = new FormData();
		fd_ActorsSearch.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_ActorsSearch.top = new FormAttachment(lblActors, LABEL_TEXT_DIFF, SWT.TOP);
		fd_ActorsSearch.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		actorsSearchText.setLayoutData(fd_ActorsSearch);

		
		
		Label lblYear = new Label(this, SWT.NONE);
		lblYear.setText("Year:");
		FormData fd_lblYear = new FormData();
		fd_lblYear.top = new FormAttachment(lblActors, LABEL_Y_SPACING);
		fd_lblYear.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblYear.setLayoutData(fd_lblYear);

		final Text minYearSearch = new Text(this, SWT.BORDER);
		FormData fd_minYearSearch = new FormData();
		fd_minYearSearch.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_minYearSearch.top = new FormAttachment(lblYear, LABEL_TEXT_DIFF, SWT.TOP);
		fd_minYearSearch.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		minYearSearch.setLayoutData(fd_minYearSearch);

	
		Label lblLanguage = new Label(this, SWT.NONE);
		FormData fd_lblLanguage = new FormData();
		fd_lblLanguage.top = new FormAttachment(lblYear, LABEL_Y_SPACING);
		fd_lblLanguage.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblLanguage.setLayoutData(fd_lblLanguage);
		lblLanguage.setText("Language:");

		final Text languageSearchText = new Text(this, SWT.BORDER);
		FormData fd_languageSearchText = new FormData();
		fd_languageSearchText.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_languageSearchText.top = new FormAttachment(lblLanguage, LABEL_TEXT_DIFF, SWT.TOP);
		fd_languageSearchText.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		languageSearchText.setLayoutData(fd_languageSearchText);


		Label lblColor = new Label(this, SWT.NONE);
		lblColor.setText("Color/BW:");
		FormData fd_lblColor = new FormData();
		fd_lblColor.top = new FormAttachment(lblLanguage, LABEL_Y_SPACING);
		fd_lblColor.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblColor.setLayoutData(fd_lblColor);
		
		final Text colorSearchText = new Text(this, SWT.BORDER);
		FormData fd_colorSearchText = new FormData();
		fd_colorSearchText.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_colorSearchText.top = new FormAttachment(lblColor, LABEL_TEXT_DIFF, SWT.TOP);
		fd_colorSearchText.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		colorSearchText.setLayoutData(fd_colorSearchText);

		
		Label lblLength = new Label(this, SWT.NONE);
		lblLength.setText("Length:");
		FormData fd_lblLength = new FormData();
		fd_lblLength.top = new FormAttachment(lblColor, LABEL_Y_SPACING);
		fd_lblLength.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblLength.setLayoutData(fd_lblLength);
		
		final Text LengthSearchText = new Text(this, SWT.BORDER);
		FormData fd_LengthSearchText = new FormData();
		fd_LengthSearchText.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_LengthSearchText.top = new FormAttachment(lblLength, LABEL_TEXT_DIFF, SWT.TOP);
		fd_LengthSearchText.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		LengthSearchText.setLayoutData(fd_LengthSearchText);

		
		Label lblRank = new Label(this, SWT.NONE);
		lblRank.setText("Rank:");
		FormData fd_lblRank = new FormData();
		fd_lblRank.top = new FormAttachment(lblLength, LABEL_Y_SPACING);
		fd_lblRank.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblRank.setLayoutData(fd_lblRank);
		
		final Text rankSearchText = new Text(this, SWT.BORDER);
		FormData fd_rankSearchText = new FormData();
		fd_rankSearchText.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_rankSearchText.top = new FormAttachment(lblRank, LABEL_TEXT_DIFF, SWT.TOP);
		fd_rankSearchText.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		rankSearchText.setLayoutData(fd_rankSearchText);

		
		Label lblDirector = new Label(this, SWT.NONE);
		FormData fd_lblDirector = new FormData();
		fd_lblDirector.top = new FormAttachment(lblRank, LABEL_Y_SPACING);
		fd_lblDirector.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		lblDirector.setLayoutData(fd_lblDirector);
		lblDirector.setText("Director:");
		
		final Text directorSearchText = new Text(this, SWT.BORDER);
		FormData fd_directorSearchText = new FormData();
		fd_directorSearchText.right = new FormAttachment(genreSearchText, 0, SWT.RIGHT);
		fd_directorSearchText.top = new FormAttachment(lblDirector, LABEL_TEXT_DIFF, SWT.TOP);
		fd_directorSearchText.left = new FormAttachment(genreSearchText, 0, SWT.LEFT);
		directorSearchText.setLayoutData(fd_directorSearchText);
		
		
		Label fcImg = new Label(this, SWT.NONE);
		FormData fd_fcImg = new FormData();
		fd_fcImg.height = GANDALF_IMAGE_SIZE;
		fd_fcImg.width = GANDALF_IMAGE_SIZE;
		fd_fcImg.top = new FormAttachment(genreSearchText, 0, SWT.TOP);
		fd_fcImg.right = new FormAttachment(100, -X_MARGIN);
		fcImg.setLayoutData(fd_fcImg);
		fcImg.setImage(new Image(getDisplay(),
    			GUIManager.class.getResourceAsStream(
    					"/images/gandalf.png")));


		btnSearch = new Button(this, SWT.PUSH);
		FormData fd_btnSearch = new FormData();
		fd_btnSearch.top = new FormAttachment(lblDirector, LABEL_Y_SPACING);
		fd_btnSearch.right = new FormAttachment(directorSearchText, 0, SWT.RIGHT);
		
		btnSearch.setLayoutData(fd_btnSearch);
		btnSearch.setText("Magic Search");
		
		
		
		btnSearch.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				btnSearch.setEnabled(false);
				
				Connection conn = MovieTools.getConn();
				
				List<SearchParam> searchParams = new LinkedList<SearchParam>();
				
				String str = genreSearchText.getText();
				if(str!=null && !str.equals(""))
				{	Integer genreID = MovieTools.getGenreID(conn,str);
					if (genreID != null){
						SearchParam tmpParam = new GenreIDParam(genreID);
						searchParams.add(tmpParam);
					}
				}
				
				str = actorsSearchText.getText(); 	
				if(str!=null && !str.equals(""))
				{
					SearchParam tmpParam = new ActorNameParam(str);
					searchParams.add(tmpParam);
				}
				
				str = minYearSearch.getText();
				if(str!=null && !str.equals(""))
				{	
					Integer year = null;
					try{
						year = Integer.parseInt(str);
					}
					catch (Exception e){}
					if (year != null){
						SearchParam tmpParam = new MinYearParam(year);
						searchParams.add(tmpParam);
					}
				}
				
				str = LengthSearchText.getText();
				if(str!=null && !str.equals(""))
				{	
					Integer length = null;
					try{
						length = Integer.parseInt(str);;
					}
					catch (Exception e){}
					if (length != null){
						SearchParam tmpParam = new MaxLengthParam(length);
						searchParams.add(tmpParam);
					}
				}
				
				str = languageSearchText.getText();
				if(str!=null && !str.equals(""))
				{	Integer languageID = MovieTools.getLanguageID(conn,str);
					if (languageID != null){
						SearchParam tmpParam = new LanguageIDParam(languageID);
						searchParams.add(tmpParam);
					}
				}
				
				str = rankSearchText.getText();
				if(str!=null && !str.equals(""))
				{	
					Float f = null;
					try{
						f = Float.parseFloat(str);
					}
					catch (Exception e){}
					if (f != null){
						SearchParam tmpParam = new MinRankParam(f);
						searchParams.add(tmpParam);
					}
				}
				
				str = directorSearchText.getText();
				if(str!=null && !str.equals(""))
				{	
					SearchParam tmpParam= new DirectorNameParam(str);
					searchParams.add(tmpParam);
				}
				
				sendParams(searchParams);
			}
		});
		

		searchResultsTable = new Table(this, SWT.BORDER | SWT.FULL_SELECTION);
		FormData fd_searchResultsTable = new FormData();
		fd_searchResultsTable.bottom = new FormAttachment(100, -Y_MARGIN);
		fd_searchResultsTable.right = new FormAttachment(fcImg, 0, SWT.RIGHT);
		fd_searchResultsTable.top = new FormAttachment(btnSearch, LABEL_Y_SPACING);
		fd_searchResultsTable.left = new FormAttachment(lblGenre, 0, SWT.LEFT);
		searchResultsTable.setLayoutData(fd_searchResultsTable);
		searchResultsTable.setHeaderVisible(true);
		searchResultsTable.setLinesVisible(true);
		
		
		//////////////////////////////////////////////////////////////////////////////////
		// Opens the movie on a new shell
		searchResultsTable.addListener(SWT.MouseDoubleClick, new Listener() {

			@Override
			public void handleEvent(Event arg0) {

				TableItem[] selection = searchResultsTable.getSelection();
				
				if (selection.length > 0) {
					LinkAdapter linkAdapter = new LinkAdapter(SearchPage.this.user);
					linkAdapter.ShowMovie(selection[0].getText(0),
							(BigInteger) selection[0].getData("id"), SearchPage.this);
				}
			}
		});
		
		// Creates sort listeners 
		for (int i = 0; i < titles.length; i++) {
			TableColumn column = new TableColumn(searchResultsTable, SWT.NONE);
			column.setText(titles[i]);
			Listener sortListener = new Listener() {
				@Override
				public void handleEvent(Event e) {
					TableItem[] items = searchResultsTable.getItems();
					Collator collator = Collator.getInstance(Locale.getDefault());
					TableColumn wcolumn = (TableColumn) e.widget;
					int index = -1;
					for (int i = 0; i < titles.length; i++) {
						if (titles[i].equals(wcolumn.getText())) {
							index = i;
							break;
						}
					}
					for (int i = 1; i < items.length; i++) {
						String value1 = items[i].getText(index);
						for (int j = 0; j < i; j++) {
							String value2 = items[j].getText(index);
							if ((value1.length() > 0 && value2.length() == 0)
									|| (value1.length() > 0 && collator
											.compare(value1, value2) < 0)) {
								String[] values = { items[i].getText(0),
										items[i].getText(1),
										items[i].getText(2),
										items[i].getText(3),
										items[i].getText(4),
										items[i].getText(5),
										items[i].getText(6),
										items[i].getText(7),
										items[i].getText(8),
										items[i].getText(9),
										items[i].getText(10),
										items[i].getText(11),
										items[i].getText(12) };
								Color itemBgClr = items[i].getBackground();
								Long id = (Long)items[i].getData("id");
								items[i].dispose();
								TableItem item = new TableItem(searchResultsTable,
										SWT.NONE, j);
								item.setText(values);
								item.setBackground(itemBgClr);
								item.setData("id", id);
								items = searchResultsTable.getItems();
								break;
							}
						}
					}
					searchResultsTable.setSortColumn(wcolumn);
				}
			};
			
			column.addListener(SWT.Selection, sortListener);
		}

	///////////////////////////////////////////////////////////////////////////
		
		
		
		
		TableColumn tblclmnName = new TableColumn(searchResultsTable, SWT.NONE);
		tblclmnName.setResizable(false);
		tblclmnName.setWidth(NAME_WIDTH);
		tblclmnName.setText("Name");
				
		TableColumn tblclmnGenre = new TableColumn(searchResultsTable,
				SWT.NONE);
		tblclmnGenre.setResizable(false);
		tblclmnGenre.setWidth(GENRE_WIDTH);
		tblclmnGenre.setText("Genre");

		
		TableColumn tblclmnLen = new TableColumn(searchResultsTable,
				SWT.NONE);
		tblclmnLen.setResizable(false);
		tblclmnLen.setWidth(LEN_WIDTH);
		tblclmnLen.setText("Length");
		
		
		TableColumn tblclmnYear = new TableColumn(searchResultsTable,
				SWT.NONE);
		tblclmnYear.setResizable(false);
		tblclmnYear.setWidth(YEAR_WIDTH);
		tblclmnYear.setText("Year");
		
		TableColumn tblclmnWatchlist = new TableColumn(searchResultsTable,
				SWT.NONE);
		tblclmnWatchlist.setResizable(false);
		tblclmnWatchlist.setWidth(WL_WIDTH);
		tblclmnWatchlist.setText("Watch List");
		
		
		TableColumn tblclmnRank = new TableColumn(searchResultsTable,
				SWT.NONE);
		tblclmnRank.setResizable(false);
		tblclmnRank.setWidth(RANK_WIDTH);
		tblclmnRank.setText("Rank");
		
		searchResultsTable.pack();
		
	}

	// Sends parameters to BL's search function
		private void sendParams(List<SearchParam> searchParams) {
			/*********************************************
			 * Set dataObject for search params
			 *********************************************/
//
//			searchMap = new HashMap<SearchParam, Object>();
//			
//			for (Entry<SearchParamEnum, Text> entry: textFields.entrySet()) {
//				if (!entry.getValue().getText().isEmpty()) {
//					searchMap.put(new SearchParam(entry.getKey(), StringParamLocation.EQUALS), entry.getValue().getText());
//				}
//			}

			final List<SearchParam> sendParams = searchParams;
			
			Thread newThread = new Thread() {
				public void run() {
					getResults(sendParams);
				}
			};

			newThread.start();
		}

		// Getting result from search function and inputing them to the table
		private void getResults(List<SearchParam> searchParams) {

			results = null;
			Connection conn = MovieTools.getConn();
			try {
				results = MovieTools.getMoviesByFilter(conn,searchParams); 
			} catch (Exception e) {
				Log.getInstance().WriteMessage("Error searching characters", e);
				GUIManager.sendStatus("Error searching Movies", StatusEnum.ERROR);
			}
			
			Runnable run = new Runnable() {
				@Override
				public void run() {
					insertResultsToContainerTable();
				}
			};

			GUIManager.sendToMainThread(run);
		}

		private void insertResultsToContainerTable() {
			
			//TODO populate the table with correct values from DB
			
			btnSearch.setEnabled(true);
			// Initialize table - clean previous results
			searchResultsTable.removeAll();

			if (results == null) {
				GUIManager.sendStatus("Could not get search results", StatusEnum.ERROR);
				return;
			}

			for (Movie m : results) {

				TableItem item = new TableItem(searchResultsTable, SWT.NONE);
				
				//this is the ID				
				item.setData("id", m.getID());
				if (m.getName() != null)
					item.setText(0, m.getName());
				
				
				List<Genre> genres = m.getGenres();
				if (genres != null && !genres.isEmpty())
					item.setText(1, m.getGenres().get(0).getGenre());
				if (m.getLength() != 0)
					item.setText(2, Integer.toString(m.getLength()));
				if (m.getYear() != 0)
					item.setText(3,Integer.toString(m.getYear()));
				
				//TODO populate WATCH LIST column with YES/NO string based on user's watchlist
				//this is what this.user is for
				//- if too complex - just remove the column from GUI completely or substitude with different interesting column 
				if (m.getMPAARating() != null)
					item.setText(5, m.getMPAARatingName());

				
				/*
				 * 
				 * Here are some fetchers for getting String form of different fields.
				 * These are all the options you have here.
				 * If you try to fetch different fields, it will take too long.
				 * 
				 * 
				 */
				
				//Fetch ID
				BigInteger id = m.getID();
				
				//Fetch name
				String name = m.getName();
				
				//Fetch formal IMDB name
				String imdbName = m.getImdbName();
				
				//Fetch country. May be null.
				String country = m.getCountryName();
				
				//Fetch language. May be null.
				String language = m.getLanguageName();
				
				//Fetch length (in minutes).
				int length = m.getLength();
				
				//Fetch MPAA rating name. May be null.
				String mpaaRating = m.getMPAARatingName();
				
				//Fetch year.
				int year = m.getYear();
				
				//Fetch genre Strings
				List<Genre> genreList = m.getGenres();
				String oneGenre = "";
				String allGenres = "";
				
				boolean isFirst = true;
				for (Genre genre : genreList){
					if (isFirst){
						oneGenre = genre.getGenre();
						isFirst = false;
					}
					else{
						allGenres += ", ";
					}
					
					allGenres += genre.getGenre();
				}
				
				
				
			}

			for (TableColumn column : searchResultsTable.getColumns()) {
				column.pack();
			}
			
			GUIManager.sendStatus("Search returned " + results.size() + " results", StatusEnum.INFORM);
			
		}
	
}
